package com.jingdianjichi.wx.controller;

import com.jingdianjichi.wx.handler.WxChatMsgFactory;
import com.jingdianjichi.wx.handler.WxChatMsgHandler;
import com.jingdianjichi.wx.utils.MessageUtil;
import com.jingdianjichi.wx.utils.SHA1;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Objects;

/**
 * 微信公众号回调接口控制器
 * 用于处理微信服务器向本服务发送的消息和事件，以及验证消息的真实性。
 * 包括接收消息、事件和验证服务器地址的有效性。
 *
 * @author: WuYimin
 * @date: 2024-02-10
 */
@RestController
@Slf4j
public class CallBackController {

	// 与微信公众平台上设置的Token保持一致，用于计算签名
	private static final String token = "dasdasdadwqewefwfwefwwqw";

	@Resource
	private WxChatMsgFactory wxChatMsgFactory;

	@RequestMapping("/test")
	public String test() {
		return "测试";
	}

	/**
	 * 微信公众平台验证服务器地址的有效性
	 *
	 * @param signature 微信加密签名
	 * @param timestamp 时间戳
	 * @param nonce     随机数
	 * @param echostr   随机字符串
	 * @return 验证通过返回echostr, 验证失败返回"unknown"
	 */
	@GetMapping("callback")
	public String callback(@RequestParam("signature") String signature,
						   @RequestParam("timestamp") String timestamp,
						   @RequestParam("nonce") String nonce,
						   @RequestParam("echostr") String echostr) {
		log.info("get验签请求参数：signature:{}，timestamp:{}，nonce:{}，echostr:{}",
				signature, timestamp, nonce, echostr);
		// 计算SHA1签名
		String shaStr = SHA1.getSHA1(token, timestamp, nonce, "");
		// 校验签名
		if (signature.equals(shaStr)) {
			return echostr;
		}
		return "unknown";
	}

	/**
	 * 处理微信服务器发送的消息和事件
	 *
	 * @param requestBody 请求体内容
	 * @param signature 微信加密签名
	 * @param timestamp 时间戳
	 * @param nonce 随机数
	 * @param msgSchostr 非必需，消息加密字符串
	 * @return 响应微信服务器的消息内容
	 */
	@PostMapping(value = "callback", produces = "application/xml;charset=UTF-8")
	public String callback(
			@RequestBody String requestBody,
			@RequestParam("signature") String signature,
			@RequestParam("timestamp") String timestamp,
			@RequestParam("nonce") String nonce,
			@RequestParam(value = "msgSchostr", required = false) String msgSchostr
	) {
		log.info("接收到微信消息：requestBody：{}", requestBody);
		// 解析消息内容
		Map<String, String> messageMap = MessageUtil.parseXml(requestBody);
		// 获取消息类型和事件类型
		// MsgType: 消息类型，如text、image、event等。
		// Event: 事件类型，仅当MsgType为event时存在，如subscribe（订阅）、unsubscribe（取消订阅）等。
		// Content: 文本消息内容，仅当MsgType为text时有值。
		String msgType = messageMap.get("MsgType");
		String event = messageMap.get("Event") == null ? "" : messageMap.get("Event");
		log.info("msgType：{}，event：{}", msgType, event);
		// 根据消息类型和事件类型获取对应的处理器
		StringBuilder sb = new StringBuilder();
		sb.append(msgType);
		if(!StringUtils.isEmpty(event)) {
			sb.append(".");
			sb.append(event);
		}
		// 拼接后的结果我们这里主要关注两种事件，一种是消息文本事件（text），一种是用户关注事件（event.subscribe）
		String msgTypeKey = sb.toString();
		WxChatMsgHandler wxChatMsgHandler = wxChatMsgFactory.getHandlerByMsgType(msgTypeKey);
		// 如果没有获取到指定的消息处理器，不做处理
		if (Objects.isNull(wxChatMsgHandler)) {
			return "unknown";
		}
		// 处理消息并生成回复内容
		String replyContent = wxChatMsgHandler.dealMsg(messageMap);

		log.info("replyContent：{}",replyContent);
		return replyContent;
	}

}

//  微信服务器与你的服务器进行交互时，会发送特定格式的XML数据包
// <xml>
//  <ToUserName><![CDATA[oBkL56ADxOQDD14nzS0VPLbu5dXQ]]></ToUserName>  oBkL56ADxOQDD14nzS0VPLbu5dXQ 用户的微信号
//  <FromUserName><![CDATA[gh_26eee70dd751]]></FromUserName>   gh_26eee70dd751  是公众号的微信号
//  <CreateTime>12345678</CreateTime>
//  <MsgType><![CDATA[text]]></MsgType>
//  <Content><![CDATA[您当前的验证码是：537！ 5分钟内有效]]></Content>
//</xml>

// MsgType: 消息类型，如text、image、event等。
// Event: 事件类型，仅当MsgType为event时存在，如subscribe（订阅）、unsubscribe（取消订阅）等。
// Content: 文本消息内容，仅当MsgType为text时有值。

// 消息处理
// 解析消息: 使用工具类（如MessageUtil）解析POST请求的XML数据，获取消息或事件的具体信息。
// 处理消息: 根据MsgType和Event（如果存在）确定消息的具体类型，然后交给相应的处理器（WxChatMsgHandler）进行处理。这里使用了一个工厂类（WxChatMsgFactory）来管理不同类型消息的处理器。
// 生成回复: 消息处理器根据业务逻辑处理消息，并生成回复消息的XML格式数据返回给微信服务器，以实现自动回复功能。